package tge

import (
	"net"
	"sync"
	"time"
	"errors"
)

type UdpAgent struct {
	conn 	*udpConn
	agent 	Agent
	dt		int		// udp 连接的超时时间
}

type UdpServer struct {
	Addrs		map[string]*net.UDPAddr
	Conns		map[net.Addr]*UdpAgent
	Parser		*MsgParser
	TimeOut		int 		// 每个 udp 的超时时间
	CreateAgent	func(Conn) Agent

	IsStarted	bool
	closeSig	chan bool	// 关闭信号
	conn 		*net.UDPConn
	mu 			sync.RWMutex
}

func NewUdpServer() *UdpServer {
	s := &UdpServer{}
	s.Addrs		= make(map[string]*net.UDPAddr)
	s.Conns		= make(map[net.Addr]*UdpAgent)
	s.Parser 	= NewMsgParser()
	s.TimeOut	= 15
	s.IsStarted = false
	s.closeSig = make(chan bool)
	return s
}

// func (s *UdpServer)SetReceiver(fn func(string, []byte)) {
// 	s.Receiver = fn
// }

// udp 接收数据
func (s *UdpServer)onMessage(raddr *net.UDPAddr, msg []byte) {
	ret, err := s.Parser.ParseMsg(msg)
	if nil != err {
		logger.Println(err)
		return
	}

	s.mu.Lock()
	if conn, ok := s.Conns[raddr]; ok {
		conn.conn.Read(ret)
	} else {
		conn := NewUdpConn(raddr, s)
		agent := s.CreateAgent(conn)
		go agent.Run()
		s.Conns[raddr] = &UdpAgent{conn, agent, 0}
		conn.Read(ret)
	}
	s.mu.Unlock()

	// if s.Receiver != nil {
	// 	s.Receiver(raddr.String(), ret)
	// }

	if len(ret) + s.Parser.GetPacketLenByte() < len(msg) {
		s.onMessage(raddr, msg[len(ret) + s.Parser.GetPacketLenByte():])
	}
}

func (s *UdpServer) Update() {
	s.mu.Lock()
	defer s.mu.Unlock()
	for k, v := range s.Conns {
		v.dt = v.dt + 1
		if v.dt >= s.TimeOut {
			v.agent.Close()
			delete(s.Conns, k)
		}
	}
}

func (s *UdpServer) Send(to string, msg... []byte) (int, error) {
	if s.conn != nil {
		raddr, err := net.ResolveUDPAddr("udp", to)
		if err == nil {
			ret, err := s.Parser.BuildMsg(msg...)
			if err != nil {
				return 0, err
			}
			return s.conn.WriteToUDP(ret, raddr)
		}
	}
	return 0, errors.New("no conn server")
}

func (s *UdpServer) SendTo(raddr *net.UDPAddr, msg... []byte) (int, error) {
	if s.conn != nil {
		ret, err := s.Parser.BuildMsg(msg...)
		if err != nil {
			return 0, err
		}
		return s.conn.WriteToUDP(ret, raddr)
	}
	return 0, errors.New("no conn server")
}

func (s *UdpServer) startUpdate() {
	tick := time.NewTicker(1 * time.Second)
	defer tick.Stop()
	for {
		select {
		case <- tick.C:
			s.Update()
		case <- s.closeSig:
			return
		}
	}
}

func (s *UdpServer) StartServer(port string) {
	if s.IsStarted {
		logger.Println("Udp Server is started!")
		return
	}

	host := ":" + port
	addr, err := net.ResolveUDPAddr("udp", host)
	if err != nil {
		logger.Println(err)
		return
	}

	cn, err := net.ListenUDP("udp", addr)
	if err != nil {
		logger.Println(err)
		return
	}
	s.conn = cn
	defer s.conn.Close()

	s.IsStarted = true

	logger.Println("Start Udp Server on", port)

	go s.startUpdate()

	var buf [65535]byte
	for {
		n, raddr, err := s.conn.ReadFromUDP(buf[0:])
		if err != nil {
			logger.Println(err)
			break
		} else if n > 0 {
			tmp := make([]byte, n)
			copy(tmp, buf[0:n])
			s.onMessage(raddr, tmp)
		}
	}

	s.IsStarted = false
}

func (s *UdpServer) Close() {
	if !s.IsStarted {
		logger.Println("Udp Server isn't started")
		return
	}

	s.conn.Close()
	close(s.closeSig)
	logger.Println("Udp Server is closed")
}